package com.ssy.lingxi.enhance.serviceimpl.supplier;

import cn.hutool.core.collection.CollectionUtil;
import com.querydsl.core.BooleanBuilder;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.enhance.constant.*;
import com.ssy.lingxi.enhance.entity.InnerWorkflowRecordDO;
import com.ssy.lingxi.enhance.entity.ProduceNoticeOrderDO;
import com.ssy.lingxi.enhance.entity.ProduceNoticeOrderDetailDO;
import com.ssy.lingxi.enhance.entity.QProduceNoticeOrderDO;
import com.ssy.lingxi.enhance.handler.async.MessageAsyncService;
import com.ssy.lingxi.enhance.handler.async.OrderAsyncService;
import com.ssy.lingxi.enhance.handler.async.ReportAsyncService;
import com.ssy.lingxi.enhance.handler.jpa.QueryDslUtil;
import com.ssy.lingxi.enhance.model.dto.AddProduceNoticeOrderDTO;
import com.ssy.lingxi.enhance.model.dto.CommonIdDTO;
import com.ssy.lingxi.enhance.model.dto.CommonIdListDTO;
import com.ssy.lingxi.enhance.model.dto.UpdateProduceNoticeOrderDTO;
import com.ssy.lingxi.enhance.model.qo.ProduceNoticeOrderQO;
import com.ssy.lingxi.enhance.model.vo.ProduceNoticeOrderListVO;
import com.ssy.lingxi.enhance.repository.InnerWorkflowRecordRepository;
import com.ssy.lingxi.enhance.repository.OuterWorkflowRecordRepository;
import com.ssy.lingxi.enhance.repository.ProduceNoticeOrderDetailRepository;
import com.ssy.lingxi.enhance.repository.ProduceNoticeOrderRepository;
import com.ssy.lingxi.enhance.service.supplier.SupplierToBeAddService;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.report.api.enums.EnhanceSupplierOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.workflow.api.feign.ProcessFeign;
import com.ssy.lingxi.workflow.api.model.contant.ProcessEnum;
import com.ssy.lingxi.workflow.api.model.contant.ProcessTaskStatusEnum;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskExecuteVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskStartVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 加工能力 - 指派生产通知单(供应商) - 待新增生产通知单 - 业务实现层
 * @author fhj
 * @date 2020/10/20
 * @version 2.0.0
 */
@Slf4j
@Service
public class SupplierToBeAddServiceImpl implements SupplierToBeAddService {

    @Resource
    private ProcessFeign processFeign;
    @Resource
    private QueryDslUtil queryDslUtil;
    @Resource
    private ProduceNoticeOrderRepository produceNoticeOrderRepository;
    @Resource
    private ProduceNoticeOrderDetailRepository produceNoticeOrderDetailRepository;
    @Resource
    private InnerWorkflowRecordRepository innerWorkflowRecordRepository;
    @Resource
    private OuterWorkflowRecordRepository outerWorkflowRecordRepository;
    @Resource
    private ReportAsyncService reportAsyncService;
    @Resource
    private OrderAsyncService orderAsyncService;
    @Resource
    private MessageAsyncService messageAsyncService;

    /**
     * 新增
     * */
    @Override
    @Transactional
    public Wrapper<Void> add(AddProduceNoticeOrderDTO dto, UserLoginCacheDTO user) {
        //校验
        if(dto.getDeliveryType().equals(DeliveryTypeEnum.LOGISTICS.getCode())) {
            if(dto.getReceiverAddressId() == null
                    || StringUtils.isBlank(dto.getReceiveAddress())
                    || StringUtils.isBlank(dto.getReceiveUserName())
                    || StringUtils.isBlank(dto.getReceiveUserTel())) {
                return Wrapper.fail(ResponseCode.ENHANCE_WHEN_DELIVERY_TYPE_IS_LOGISTICS_RECEIVE_NOT_NULL);
            }
        }

        //新增生产通知单
        ProduceNoticeOrderDO produceNoticeOrder = new ProduceNoticeOrderDO();
        BeanUtils.copyProperties(dto, produceNoticeOrder);
        produceNoticeOrder.setProcessTotalPrice(dto.getDetails().stream().mapToDouble(AddProduceNoticeOrderDTO.ProduceNoticeOrderDetailDTO::getProcessTotalPrice).sum());
        produceNoticeOrder.setOtherAsk(dto.getOtherAsk());
        produceNoticeOrder.setSupplierMemberId(user.getMemberId());
        produceNoticeOrder.setSupplierRoleId(user.getMemberRoleId());
        produceNoticeOrder.setSupplierName(user.getCompany());
        produceNoticeOrder.setSupplierInnerTaskType(ProcessEnum.PNO_SUPPLIER_INNER_VERIFY.getCode());
        produceNoticeOrder.setProcessInnerTaskType(ProcessEnum.PNO_PROCESS_INNER_VERIFY.getCode());
        produceNoticeOrder.setOuterTaskType(dto.getOuterTaskType());
        produceNoticeOrder.setSupplierInnerProcessKey(ProcessEnum.PNO_SUPPLIER_INNER_VERIFY.getProcessKey());
        produceNoticeOrder.setProcessInnerProcessKey(ProcessEnum.PNO_PROCESS_INNER_VERIFY.getProcessKey());
        produceNoticeOrder.setOuterProcessKey(
                dto.getOuterTaskType().equals(ProcessEnum.PNO_OUTER_VERIFY.getCode()) ?
                        ProcessEnum.PNO_OUTER_VERIFY.getProcessKey() : ProcessEnum.PNO_MANUAL_DELIVERY_OUTER_VERIFY.getProcessKey()
        );
        produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);

        //批量保存生产通知单明细
        List<ProduceNoticeOrderDetailDO> details = dto.getDetails().stream().map(d -> {
            if(dto.getSource().equals(SourceEnum.ORDER.getCode())) {
                if(d.getOrderId() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_ORDER_ID_NOT_NULL);
                }
                if(StringUtils.isBlank(d.getOrderNo())) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_ORDER_NO_NOT_NULL);
                }
                if(d.getOrderDetailId() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_ORDER_DETAIL_ID_NOT_NULL);
                }
                if(d.getPurchaseCount() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_PURCHASE_COUNT_NOT_NULL);
                }
                if(d.getSurplusProcessNum() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_SURPLUS_PROCESS_NUM_NOT_NULL);
                }
                /*
                    本应该判断每个明细里面不允许出现加工数量大于剩余加工数量的现象,
                    但考虑到卖家申请加工单后, 加工商按期加工并发货, 然后卖家收到货之后, 发现加工的商品里面有一部分是损坏的,
                    这时候想针对这些损坏的数量重新再申请加工单时, 发现剩余加工数量小于损坏数量, 这时候因判断导致不给卖家重新加工不太合理,
                    因此让页面直接提示"加工数量大于剩余数量, 是否继续加工"的窗口。
                */
            }
            ProduceNoticeOrderDetailDO detail = new ProduceNoticeOrderDetailDO();
            BeanUtils.copyProperties(d, detail);
            detail.setProduceNoticeOrderId(produceNoticeOrder.getId());
            detail.setProperty(d.getProperty());
            detail.setNotDeliverNum(d.getProcessNum());
            return detail;
        }).collect(Collectors.toList());
        produceNoticeOrderDetailRepository.saveAll(details);

        //调用工作流服务 -> 开启供应商内部工作流
        TaskStartVO taskStartVO = new TaskStartVO();
        taskStartVO.setProcessKey(produceNoticeOrder.getSupplierInnerProcessKey());
        taskStartVO.setMemberId(produceNoticeOrder.getSupplierMemberId());
        taskStartVO.setRoleId(produceNoticeOrder.getSupplierRoleId());
        taskStartVO.setDataId(produceNoticeOrder.getId());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.startSimpleProcess(taskStartVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //更新状态、供应商内部状态、供应商内部任务ID
            produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode());
            produceNoticeOrder.setSupplierInnerStatus(wrapper.getData().getStatus());
            produceNoticeOrder.setSupplierInnerTaskId(wrapper.getData().getTaskId());

            //调用工作流服务 -> 开启外部工作流
            taskStartVO.setProcessKey(produceNoticeOrder.getOuterProcessKey());
            wrapper = processFeign.startSimpleProcess(taskStartVO);
            if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
                //更新外部状态、外部任务ID、通知单号
                produceNoticeOrder.setOuterStatus(wrapper.getData().getStatus());
                produceNoticeOrder.setOuterTaskId(wrapper.getData().getTaskId());
                produceNoticeOrder.setNoticeNo("TPTYI" + produceNoticeOrder.getId());
                produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);

                //新增完生产通知单后, 判断通知单来源是否为订单加工, 如果是, 需要将生产通知单明细里的订单商品加工数量更新至订单服务对应的订单商品
                if(dto.getSource().equals(SourceEnum.ORDER.getCode())) {
                    orderAsyncService.updateOrderProductProcessNum(details, Boolean.TRUE);
                }
            }else {
                log.error("工作流服务异常:" + wrapper.getMessage());
                throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
            }
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
        }

        //调用报表服务、消息服务 -> 新增操作通知、发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(),  1L,
                null, null
        );
        messageAsyncService.sendSystemMessage(user.getMemberId(), user.getMemberRoleId(),
                MessageTemplateCode.production_order_wait_audit, Stream.of(produceNoticeOrder.getNoticeNo(), produceNoticeOrder.getSummary()).collect(Collectors.toList())
        );

        return Wrapper.success();
    }

    /**
     * 修改
     * */
    @Override
    @Transactional
    public Wrapper<Void> update(UpdateProduceNoticeOrderDTO dto, UserLoginCacheDTO user) {
        //校验
        if(dto.getDeliveryType().equals(DeliveryTypeEnum.LOGISTICS.getCode())) {
            if(dto.getReceiverAddressId() == null
                    || StringUtils.isBlank(dto.getReceiveAddress())
                    || StringUtils.isBlank(dto.getReceiveUserName())
                    || StringUtils.isBlank(dto.getReceiveUserTel())) {
                return Wrapper.fail(ResponseCode.ENHANCE_WHEN_DELIVERY_TYPE_IS_LOGISTICS_RECEIVE_NOT_NULL);
            }
        }

        //根据ID获取生产通知单详情
        ProduceNoticeOrderDO produceNoticeOrder = produceNoticeOrderRepository.findById(dto.getId()).orElse(null);
        if(produceNoticeOrder == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(!(produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode())
                || produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.SUPPLIER_NOT_PASSED1.getCode())
                || produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.SUPPLIER_NOT_PASSED2.getCode())
                || produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.PROCESS_NOT_ACCEPTED.getCode()))) {
            return Wrapper.fail("只能修改待提交审核、审核不通过、不接受通知单的生产通知单");
        }

        //如果通知单来源为加工订单且内部状态是为待提交审核状态的话, 需要在修改之前先扣减订单服务里的订单商品已加工数量（避免刚新增完叠加了已加工数量后再修改导致还没去扣减已加工数量就再次叠加场景）
        if(produceNoticeOrder.getSource().equals(SourceEnum.ORDER.getCode())
                && produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode())) {
            List<ProduceNoticeOrderDetailDO> details = produceNoticeOrderDetailRepository.findByProduceNoticeOrderId(dto.getId());
            orderAsyncService.updateOrderProductProcessNum(details, Boolean.FALSE);
        }

        //获取修改生产通知单之前的状态, 用于判断是否新增待办和发送系统消息
        Integer status = produceNoticeOrder.getStatus();

        //修改生产通知单
        produceNoticeOrder.setProcessTotalPrice(dto.getDetails().stream().mapToDouble(UpdateProduceNoticeOrderDTO.ProduceNoticeOrderDetailDTO::getProcessTotalPrice).sum());
        produceNoticeOrder.setProcessInnerStatus(null);
        produceNoticeOrder.setCause(null);
        produceNoticeOrder.setSummary(dto.getSummary());
        produceNoticeOrder.setSupplierMemberId(user.getMemberId());
        produceNoticeOrder.setSupplierRoleId(user.getMemberRoleId());
        produceNoticeOrder.setSupplierName(user.getCompany());
        produceNoticeOrder.setProcessMemberId(dto.getProcessMemberId());
        produceNoticeOrder.setProcessRoleId(dto.getProcessRoleId());
        produceNoticeOrder.setProcessName(dto.getProcessName());
        produceNoticeOrder.setSource(dto.getSource());
        produceNoticeOrder.setDeliveryDate(dto.getDeliveryDate());
        produceNoticeOrder.setDeliveryType(dto.getDeliveryType());
        produceNoticeOrder.setReceiverAddressId(dto.getReceiverAddressId());
        produceNoticeOrder.setReceiveAddress(dto.getReceiveAddress());
        produceNoticeOrder.setReceiveUserName(dto.getReceiveUserName());
        produceNoticeOrder.setReceiveUserTel(dto.getReceiveUserTel());
        produceNoticeOrder.setOtherAsk(dto.getOtherAsk());
        produceNoticeOrder.setOuterTaskType(dto.getOuterTaskType());
        produceNoticeOrder.setOuterProcessKey(
                dto.getOuterTaskType().equals(ProcessEnum.PNO_OUTER_VERIFY.getCode()) ?
                        ProcessEnum.PNO_OUTER_VERIFY.getProcessKey() : ProcessEnum.PNO_MANUAL_DELIVERY_OUTER_VERIFY.getProcessKey()
        );
        produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);

        //删除生产通知单明细, 内部工作流记录, 外部工作流记录
        produceNoticeOrderDetailRepository.deleteByProduceNoticeOrderId(dto.getId());
        innerWorkflowRecordRepository.deleteByProduceNoticeOrderId(dto.getId());
        outerWorkflowRecordRepository.deleteByProduceNoticeOrderId(dto.getId());

        //批量新增生产通知单明细
        List<ProduceNoticeOrderDetailDO> details = dto.getDetails().stream().map(d -> {
            if(dto.getSource().equals(SourceEnum.ORDER.getCode())) {
                if(d.getOrderId() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_ORDER_ID_NOT_NULL);
                }
                if(StringUtils.isBlank(d.getOrderNo())) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_ORDER_NO_NOT_NULL);
                }
                if(d.getOrderDetailId() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_ORDER_DETAIL_ID_NOT_NULL);
                }
                if(d.getPurchaseCount() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_PURCHASE_COUNT_NOT_NULL);
                }
                if(d.getSurplusProcessNum() == null) {
                    throw new BusinessException(ResponseCode.ENHANCE_WHEN_SOURCE_IS_ORDER_SURPLUS_PROCESS_NUM_NOT_NULL);
                }
                /*
                    本应该判断每个明细里面不允许出现加工数量大于剩余加工数量的现象,
                    但考虑到卖家申请加工单后, 加工商按期加工并发货, 然后卖家收到货之后, 发现加工的商品里面有一部分是损坏的,
                    这时候想针对这些损坏的数量重新再申请加工单时, 发现剩余加工数量小于损坏数量, 这时候因判断导致不给卖家重新加工不太合理,
                    因此让页面直接提示"加工数量大于剩余数量, 是否继续加工"的窗口。
                */
            }
            ProduceNoticeOrderDetailDO detail = new ProduceNoticeOrderDetailDO();
            BeanUtils.copyProperties(d, detail);
            detail.setProduceNoticeOrderId(produceNoticeOrder.getId());
            detail.setProperty(d.getProperty());
            detail.setNotDeliverNum(d.getProcessNum());
            return detail;
        }).collect(Collectors.toList());
        produceNoticeOrderDetailRepository.saveAll(details);

        //调用工作流服务 -> 开启供应商内部工作流
        TaskStartVO taskStartVO = new TaskStartVO();
        taskStartVO.setProcessKey(produceNoticeOrder.getSupplierInnerProcessKey());
        taskStartVO.setMemberId(produceNoticeOrder.getSupplierMemberId());
        taskStartVO.setRoleId(produceNoticeOrder.getSupplierRoleId());
        taskStartVO.setDataId(produceNoticeOrder.getId());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.startSimpleProcess(taskStartVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //更新状态、供应商内部状态、供应商内部任务ID
            produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode());
            produceNoticeOrder.setSupplierInnerStatus(wrapper.getData().getStatus());
            produceNoticeOrder.setSupplierInnerTaskId(wrapper.getData().getTaskId());

            //调用工作流服务 -> 开启外部工作流
            taskStartVO.setProcessKey(produceNoticeOrder.getOuterProcessKey());
            wrapper = processFeign.startSimpleProcess(taskStartVO);
            if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
                //更新外部状态、外部任务ID
                produceNoticeOrder.setOuterStatus(wrapper.getData().getStatus());
                produceNoticeOrder.setOuterTaskId(wrapper.getData().getTaskId());
                produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);

                //修改完生产通知单后, 判断通知单来源是否为订单加工, 如果是, 需要将生产通知单明细里的订单商品加工数量更新至订单服务对应的订单商品
                if(dto.getSource().equals(SourceEnum.ORDER.getCode())) {
                    orderAsyncService.updateOrderProductProcessNum(details, Boolean.TRUE);
                }
            }else {
                log.error("工作流服务异常:" + wrapper.getMessage());
                throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
            }
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
        }

        //如果状态是为待提交审核状态的话, 就不需要新增待办和发送系统消息了。（避免待办数量统计错误或发送重复系统消息）
        if(!status.equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode())) {
            //调用报表服务、消息服务 -> 新增操作通知、发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
            reportAsyncService.addOperateNotice(
                    user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                    EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(),  1L,
                    null, null
            );
            messageAsyncService.sendSystemMessage(user.getMemberId(), user.getMemberRoleId(),
                    MessageTemplateCode.production_order_wait_audit, Stream.of(produceNoticeOrder.getNoticeNo(), produceNoticeOrder.getSummary()).collect(Collectors.toList())
            );
        }

        return Wrapper.success();
    }

    /**
     * 列表
     * */
    @Override
    public Wrapper<PageData<ProduceNoticeOrderListVO>> list(ProduceNoticeOrderQO qo, UserLoginCacheDTO user) {
        //查询表实体 - 生产通知单
        QProduceNoticeOrderDO pno = QProduceNoticeOrderDO.produceNoticeOrderDO;

        //查询条件构造 - 必要条件
        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(pno.supplierMemberId.eq(user.getMemberId()));
        predicates.and(pno.supplierRoleId.eq(user.getMemberRoleId()));
        predicates.and(pno.outerStatus.in(PNOOuterStatusEnum.getSupplierToBeAddListStatus()));
        predicates.and(pno.supplierInnerStatus.in(PNOSupplierInnerStatusEnum.getSupplierToBeAddListStatus()));

        return Wrapper.success(queryDslUtil.getSupplierPNOList(qo, pno, predicates));
    }

    /**
     * 删除
     * */
    @Override
    @Transactional
    public Wrapper<Void> delete(CommonIdDTO dto, UserLoginCacheDTO user) {
        //根据ID获取生产通知单详情
        ProduceNoticeOrderDO produceNoticeOrder = produceNoticeOrderRepository.findById(dto.getId()).orElse(null);

        //校验
        if(produceNoticeOrder == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(!produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode())) {
            return Wrapper.fail(ResponseCode.ENHANCE_ONLY_DELETE_INNER_STATUS_AS_TO_BE_EXAM);
        }

        //删除生产通知单以及关联的明细、内部工作流记录、外部工作流记录
        produceNoticeOrderRepository.deleteById(dto.getId());
        innerWorkflowRecordRepository.deleteByProduceNoticeOrderId(dto.getId());
        outerWorkflowRecordRepository.deleteByProduceNoticeOrderId(dto.getId());
        List<ProduceNoticeOrderDetailDO> details = produceNoticeOrderDetailRepository.deleteByProduceNoticeOrderId(dto.getId());

        //删除完生产通知单后, 判断通知单来源是否为订单加工, 如果是, 需要将生产通知单明细里的订单商品加工数量更新至订单服务对应的订单商品
        if(produceNoticeOrder.getSource().equals(SourceEnum.ORDER.getCode())) {
            orderAsyncService.updateOrderProductProcessNum(details, Boolean.FALSE);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                null,  null,
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(), 1L
        );

        return Wrapper.success();
    }

    /**
     * 批量删除
     * */
    @Override
    @Transactional
    public Wrapper<Void> batchDelete(CommonIdListDTO dto, UserLoginCacheDTO user) {
        //根据ID集合获取生产通知单集合
        List<ProduceNoticeOrderDO> produceNoticeOrderList = produceNoticeOrderRepository.findAllById(dto.getIdList());

        //校验
        if(CollectionUtil.isEmpty(produceNoticeOrderList)) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(produceNoticeOrderList.stream().anyMatch(a -> !a.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode()))) {
            return Wrapper.fail(ResponseCode.ENHANCE_ONLY_DELETE_INNER_STATUS_AS_TO_BE_EXAM);
        }

        //抽取生产通知单ID集合
        List<Long> produceNoticeOrderIdList = produceNoticeOrderList.stream().map(ProduceNoticeOrderDO::getId).collect(Collectors.toList());

        //删除生产通知单以及关联的明细、内部工作流记录、外部工作流记录
        produceNoticeOrderRepository.deleteInBatch(produceNoticeOrderList);
        innerWorkflowRecordRepository.deleteByProduceNoticeOrderIdIn(produceNoticeOrderIdList);
        outerWorkflowRecordRepository.deleteByProduceNoticeOrderIdIn(produceNoticeOrderIdList);
        List<ProduceNoticeOrderDetailDO> details = produceNoticeOrderDetailRepository.deleteByProduceNoticeOrderIdIn(produceNoticeOrderIdList);

        //获取通知单来源为订单加工的生产通知单ID集合, 判断不为空的话, 需要将生产通知单明细里的订单商品加工数量更新至订单服务对应的订单商品
        produceNoticeOrderIdList = produceNoticeOrderList.stream().filter(a -> a.getSource().equals(SourceEnum.ORDER.getCode())).map(ProduceNoticeOrderDO::getId).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(produceNoticeOrderIdList)) {
            List<Long> finalProduceNoticeOrderIdList = produceNoticeOrderIdList;
            details = details.stream().filter(a -> finalProduceNoticeOrderIdList.contains(a.getProduceNoticeOrderId())).collect(Collectors.toList());
            orderAsyncService.updateOrderProductProcessNum(details, Boolean.FALSE);
        }

        //调用报表服务 -> 新增操作通知（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                null,  null,
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(), (long) dto.getIdList().size()
        );

        return Wrapper.success();
    }

    /**
     * 提交审核
     * */
    @Override
    @Transactional
    public Wrapper<Void> submitExam(CommonIdDTO dto, UserLoginCacheDTO user) {
        //根据ID获取生产通知单详情
        ProduceNoticeOrderDO produceNoticeOrder = produceNoticeOrderRepository.findById(dto.getId()).orElse(null);
        if(produceNoticeOrder == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(!produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode())) {
            return Wrapper.fail(ResponseCode.ENHANCE_ONLY_SUBMIT_INNER_STATUS_AS_TO_BE_EXAM);
        }

        //调用工作流服务 -> 执行供应商内部流程
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(produceNoticeOrder.getSupplierMemberId());
        taskExecuteVO.setRoleId(produceNoticeOrder.getSupplierRoleId());
        taskExecuteVO.setDataId(produceNoticeOrder.getId());
        taskExecuteVO.setTaskId(produceNoticeOrder.getSupplierInnerTaskId());
        taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
        taskExecuteVO.setProcessKey(produceNoticeOrder.getSupplierInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
            //记录供应商内部工作流记录
            InnerWorkflowRecordDO innerWorkflowRecord = new InnerWorkflowRecordDO();
            innerWorkflowRecord.setProduceNoticeOrderId(produceNoticeOrder.getId());
            innerWorkflowRecord.setUserId(user.getUserId());
            innerWorkflowRecord.setMemberId(user.getMemberId());
            innerWorkflowRecord.setRoleId(user.getMemberRoleId());
            innerWorkflowRecord.setType(RoleTypeEnum.SUPPLIER.getCode());
            innerWorkflowRecord.setStep(produceNoticeOrder.getSupplierInnerStatus());
            innerWorkflowRecord.setOperator(user.getUserName());
            innerWorkflowRecord.setDepartment(user.getUserOrgName());
            innerWorkflowRecord.setJobTitle(user.getUserJobTitle());
            innerWorkflowRecord.setStatus("待审核（一级）");
            innerWorkflowRecord.setOperate("新增生产通知单");
            innerWorkflowRecord.setOperateTime(System.currentTimeMillis());
            innerWorkflowRecord.setOpinion("提交审核");
            innerWorkflowRecordRepository.saveAndFlush(innerWorkflowRecord);

            //更新状态、供应商内部状态、供应商内部任务ID
            produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_SUPPLIER_EXAM1.getCode());
            produceNoticeOrder.setSupplierInnerStatus(wrapper.getData().getStatus());
            produceNoticeOrder.setSupplierInnerTaskId(wrapper.getData().getTaskId());
            produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);
        }else {
            log.error("工作流服务异常:" + wrapper.getMessage());
            throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
        }

        //调用报表服务、消息服务 -> 新增操作通知、发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_STEP1.getCode(),  1L,
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(), 1L
        );
        messageAsyncService.sendSystemMessage(user.getMemberId(), user.getMemberRoleId(),
                MessageTemplateCode.production_order_audit_step_1, Stream.of(produceNoticeOrder.getNoticeNo(), produceNoticeOrder.getSummary()).collect(Collectors.toList())
        );

        return Wrapper.success();
    }

    /**
     * 批量提交审核
     * */
    @Override
    @Transactional
    public Wrapper<Void> batchSubmitExam(CommonIdListDTO dto, UserLoginCacheDTO user) {
        //根据ID集合获取生产通知单集合
        List<ProduceNoticeOrderDO> produceNoticeOrderList = produceNoticeOrderRepository.findAllById(dto.getIdList());

        //初始化变量：提交审核成功数量（新增操作通知）、SystemMessageRequest集合（发送系统消息）
        Long flag = 0L;
        List<SystemMessageRequest> systemMessageRequestList = new ArrayList<>();

        //校验
        if(CollectionUtil.isEmpty(produceNoticeOrderList)) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(produceNoticeOrderList.stream().anyMatch(a -> !a.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT_EXAM.getCode()))) {
            return Wrapper.fail(ResponseCode.ENHANCE_ONLY_SUBMIT_INNER_STATUS_AS_TO_BE_EXAM);
        }

        //循环调用工作流服务, 调用成功时更新生产通知单和新增内部工作流记录, 调用失败直接返回, 不需要抛出异常, 因为前面调用成功的不需要回滚。
        for(ProduceNoticeOrderDO p:produceNoticeOrderList) {
            //调用工作流服务 -> 执行供应商内部流程
            TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
            taskExecuteVO.setMemberId(p.getSupplierMemberId());
            taskExecuteVO.setRoleId(p.getSupplierRoleId());
            taskExecuteVO.setDataId(p.getId());
            taskExecuteVO.setTaskId(p.getSupplierInnerTaskId());
            taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
            taskExecuteVO.setProcessKey(p.getSupplierInnerProcessKey());
            Wrapper<SimpleTaskCompleteVO> wrapper = processFeign.completeSimpleTask(taskExecuteVO);
            if(ResponseCode.SUCCESS.getCode() == wrapper.getCode()) {
                //记录供应商内部工作流记录
                InnerWorkflowRecordDO innerWorkflowRecord = new InnerWorkflowRecordDO();
                innerWorkflowRecord.setProduceNoticeOrderId(p.getId());
                innerWorkflowRecord.setUserId(user.getUserId());
                innerWorkflowRecord.setMemberId(user.getMemberId());
                innerWorkflowRecord.setRoleId(user.getMemberRoleId());
                innerWorkflowRecord.setType(RoleTypeEnum.SUPPLIER.getCode());
                innerWorkflowRecord.setStep(p.getSupplierInnerStatus());
                innerWorkflowRecord.setOperator(user.getUserName());
                innerWorkflowRecord.setDepartment(user.getUserOrgName());
                innerWorkflowRecord.setJobTitle(user.getUserJobTitle());
                innerWorkflowRecord.setStatus("待审核（一级）");
                innerWorkflowRecord.setOperate("新增生产通知单");
                innerWorkflowRecord.setOperateTime(System.currentTimeMillis());
                innerWorkflowRecord.setOpinion("提交审核");
                innerWorkflowRecordRepository.saveAndFlush(innerWorkflowRecord);

                //更新状态、供应商内部状态、供应商内部任务ID
                p.setStatus(PNOAllStatusEnum.TO_BE_SUPPLIER_EXAM1.getCode());
                p.setSupplierInnerStatus(wrapper.getData().getStatus());
                p.setSupplierInnerTaskId(wrapper.getData().getTaskId());
                produceNoticeOrderRepository.saveAndFlush(p);

                //每保存一次，新增操作通知、发送系统消息各加一
                flag++;
                SystemMessageRequest systemMessageRequest = new SystemMessageRequest();
                systemMessageRequest.setMemberId(p.getSupplierMemberId());
                systemMessageRequest.setRoleId(p.getSupplierRoleId());
                systemMessageRequest.setMessageNotice(MessageTemplateCode.production_order_audit_step_1);
                systemMessageRequest.setParams(Stream.of(p.getNoticeNo(), p.getSummary()).collect(Collectors.toList()));
                systemMessageRequestList.add(systemMessageRequest);
            }else {
                //保存成功的生产通知单需要调用报表服务和消息服务 -> 新增操作通知、批量发送系统消息
                if(flag > 0) {
                    reportAsyncService.addOperateNotice(
                            user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                            EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_STEP1.getCode(),  flag,
                            EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(), flag
                    );
                    messageAsyncService.batchSendSystemMessage(systemMessageRequestList);
                }
                log.error("工作流服务异常:" + wrapper.getMessage());
                return Wrapper.fail(ResponseCode.ENHANCE_WORKFLOW_ERROR);
            }
        }

        //调用报表服务、消息服务 -> 新增操作通知、批量发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNotice(
                user.getMemberId(), user.getMemberRoleId(), OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode(),
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_STEP1.getCode(),  flag,
                EnhanceSupplierOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode(), flag
        );
        messageAsyncService.batchSendSystemMessage(systemMessageRequestList);

        return Wrapper.success();
    }
}
